package io.gitee.wl4837.alatool.core.getter;

import io.gitee.wl4837.alatool.core.lang.MethodType;
import io.gitee.wl4837.alatool.core.util.MethodUtil;

import java.lang.invoke.SerializedLambda;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @author Kingood
 */
public interface MethodBaseInfo {

    default String getMethodName() {
        return getSerializedLambda().getImplMethodName();
    }

    default Class<?>[] getParamsClass() {
        MethodType methodType = MethodUtil.getMethodType(getSerializedLambda().getImplMethodSignature());
        return methodType.getParameterTypes();
    }

    default Class<?> getFirstParamClass() {
        Class<?>[] paramsClass = getParamsClass();
        if (paramsClass.length > 0) {
            return paramsClass[0];
        }
        return null;
    }

    default Class<?> getReturnClass() {
        MethodType methodType = MethodUtil.getMethodType(getSerializedLambda().getImplMethodSignature());
        return methodType.getReturnType();
    }

    default Class<?> getObjectClass() {
        SerializedLambda lambda = getSerializedLambda();
        try {
            return Class.forName(lambda.getImplClass().replace("/", "."));
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    default Method getMethod() {
        try {
            return getObjectClass().getMethod(getMethodName(), getParamsClass());
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }

    default SerializedLambda getSerializedLambda() {
        Method method;
        try {
            method = getClass().getDeclaredMethod("writeReplace");
            method.setAccessible(true);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
        try {
            return (SerializedLambda) method.invoke(this);
        } catch (IllegalAccessException | InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }

}
